#include "mainwindow.h"
#include "ui_mainwindow.h"
//文件读取有关头文件
#include<QFileDialog>
#include<QJsonDocument>
#include<QJsonParseError>
#include<QJsonObject>
#include<QJsonArray>
#include"getgeometry.h"
//错误信息
#include<QMessageBox>
#include<QDebug>
#include"postgislinker.h"
#include"ogrsf_frmts.h"
#include"glrenderer.h"



MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    postGISLinker = new class postGISLinker;
    ui->setupUi(this);
    //连接信号和槽
    connect(ui->actionOpenFile,SIGNAL(triggered()),this,SLOT(onFileOpen()),Qt::AutoConnection);
    connect(ui->actionKernelAnalysis,SIGNAL(triggered()),this,SLOT(onKernelAnalysis()),Qt::AutoConnection);
    connect(ui->actionLinkServer,SIGNAL(triggered()),this,SLOT(LinkToPostGIS()),Qt::AutoConnection);
    connect(postGISLinker,SIGNAL(drawNow(geoLayer*)),this,SLOT(drawmap(geoLayer*)),Qt::AutoConnection);
    connect(ui->actionGridIndex,SIGNAL(changed()),this,SLOT(onActionGridIndexPressed()),Qt::AutoConnection);
    connect(ui->actionQuadTreeIndex,SIGNAL(changed()),this,SLOT(onActionQuadTreeIndexPressed()),Qt::AutoConnection);
}

MainWindow::~MainWindow()
{
    delete ui;
}

//菜单->文件->打开 触发函数
void MainWindow::onFileOpen()
{
    //从FileDialog获取文件路径
    filePath=QFileDialog::getOpenFileName(nullptr,QFileDialog::tr("打开文件"),"",QFileDialog::tr("GeoJson文件 (*.json);;shp文件 (*.shp)"));
    if(filePath.contains("json"))
    {
        readGeoJson();
    }
    else if(filePath.contains("shp"))
    {
        readShp();
    }
    if(filePath.isEmpty()==false)
    {
       drawmap();
    }
}


    //打开文件绘制窗口，进行绘制
void MainWindow::drawmap()
{
    //每打开一个文件就创建一个新的文件绘制窗口
    FileDrawWindow *f=new FileDrawWindow();
    fileDrawWindows.append(f);
    f->setWindowTitle(filePath);
    QStringList list=filePath.split(QRegExp("\\W+"), QString::SkipEmptyParts);//删除路径中所有符号
    list.removeLast();//删除文件后缀
    maps.last()->geoLayers[0]->name=list.last();//一般文件都是单图层
    maps.last()->isProjected=false;
    f->openglWidget->map=*(maps.last());
    f->show();
    //在读取文件后可选呈现的索引
    if(ui->menu_4->isEnabled()==false)
    {
        ui->menu_4->setEnabled(true);
    }
}

void MainWindow::drawmap(geoLayer* layer)
{
    geoMap* map=new geoMap();
    map->geoLayers.append(layer);
    map->isProjected=true;
    maps.append(map);

    //每打开一个文件就创建一个新的文件绘制窗口
    FileDrawWindow *f=new FileDrawWindow();
    fileDrawWindows.append(f);
    f->setWindowTitle(layer->name);
    f->openglWidget->map=*(maps.last());
    f->show();

    //在读取文件后可选呈现的索引
    if(ui->menu_4->isEnabled()==false)
    {
        ui->menu_4->setEnabled(true);
    }
}
void MainWindow::LinkToPostGIS()
{
    postGISLinker->show();
}

//读取GeoJson
void MainWindow:: readGeoJson()
{
    geoMap* map=new geoMap();
    maps.append(map);
    geoLayer *layer=new geoLayer();
    map->geoLayers.append(layer);

    //读取文件到data
    QFile file(filePath);
    file.open(QIODevice::ReadOnly);
    QByteArray data=file.readAll();
    file.close();

    //创建QJson相关类，检查文件错误
    QJsonParseError parseJsonErr;
    QJsonDocument jsdoc=QJsonDocument::fromJson(data,&parseJsonErr);
    if (! (parseJsonErr.error == QJsonParseError::NoError)) {
        QMessageBox::about(nullptr, "提示", "配置文件错误！");
        qDebug()<<parseJsonErr.error;
        return;
    }
    if(jsdoc.isNull()==true)
    {
        QMessageBox::about(nullptr,"提示","GeoJson文件为空！");
        return;
    }

    //解析GeoJson文件
    QJsonArray features=jsdoc.object()["features"].toArray();
    geoObject *object=nullptr;
    for(int i=0;i<features.size();i++)
    {
        QJsonObject feature=features[i].toObject();

        //读取geometry
        QJsonObject geometry=feature["geometry"].toObject();
        QString type=geometry["type"].toString();

        //确定geoObject类型
        if(type=="Point")  object=new geoPoint();
        else if(type=="MultiPoint") object=new geoMultiPoint();
        else if(type=="LineString") object=new geoLineString();
        else if(type=="MultiLineString") object=new geoMultiLineString();
        else if(type=="Polygon") object=new geoPolygon();
        else if(type=="MultiPolygon") object=new geoMultiPolygon();
        object->type=type;

        layer->geoObjects.append(object);

        //这里可以细看GeoJson文件，注意中括号的嵌套关系
        QJsonArray coordinates=geometry["coordinates"].toArray();//一个coordinates数组元素代表一个简单geoObject（点、多点、线、面）
        if(type=="MultiPolygon")
        {
            for(int j=0;j<coordinates.size();j++) //size面的个数
            {
                QJsonArray coordinate=coordinates[j].toArray();
                geoPolygon *polygon=new geoPolygon();
                //读取一个面
                for(int k=0;k<coordinate.size();k++)
                {
                    QJsonArray position=coordinate[k].toArray();
                    for(int l=0;l<position.size();l++)
                    {
                        QJsonArray pos=position[l].toArray();
                        double x=pos[0].toDouble();
                        double y=pos[1].toDouble();
                        polygon->coordinates.append(QPointF(x,y));
                        polygon->projectedCoordinates.append(QPointF(x,y));
                    }
                    dynamic_cast<geoMultiPolygon *>(object)->polygons.append(polygon);
                }
             }
        }
        else if(type=="MultiLineString")
        {
            for(int j=0;j<coordinates.size();j++)
            {
                QJsonArray coordinate=coordinates[j].toArray();
                geoLineString *line=new geoLineString();
                //读取一条线
                for(int k=0;k<coordinate.size();k++)
                {
                    QJsonArray position=coordinate[k].toArray();
                    for(int l=0;l<position.size();l++)
                    {
                        QJsonArray pos=position[l].toArray();
                        double x=pos[0].toDouble();
                        double y=pos[1].toDouble();
                        line->coordinates.append(QPointF(x,y));
                        line->projectedCoordinates.append(QPointF(x,y));
                    }
                    dynamic_cast<geoMultiLineString *>(object)->lineStrings.append(line);
                }
             }
        }
        else
        {
            for(int j=0;j<coordinates.size();j++)
            {
                QJsonArray coordinate=coordinates[j].toArray();
                for(int k=0;k<coordinate.size();k++)
                {
                    QJsonArray position=coordinate[k].toArray();
                    double x=position[0].toDouble();
                    double y=position[1].toDouble();
                    object->coordinates.append(QPointF(x,y));
                    object->projectedCoordinates.append(QPointF(x,y));
                }
             }
        }

        //读取properties
        QJsonObject properties=feature["properties"].toObject();
        object->name=properties["name"].toString();
        object->adcode=properties["adcode"].toString().toInt();//QJsonValue的toInt(int defaultValue=0)函数返回输入参数，默认为0，因此不能直接将其转换为Int，而应该先转换成QString或其他类型，再用这些类型的toInt()
        object->telecode=properties["telecode"].toString().toInt();
        object->level=properties["level"].toString();
        object->childrenNum=properties["childrenNum"].toString().toInt();
    }
}

void MainWindow::readShp()
{
    //打开文件则建立一个新的map
    geoMap* map=new geoMap();
    maps.append(map);
    std::string tmp=filePath.toStdString();
    const char * cFilePath=tmp.c_str();

    //注册所有驱动
    GDALAllRegister();

    //打开shp文件
    GDALDataset *poDS = static_cast<GDALDataset*>(
           GDALOpenEx( cFilePath, GDAL_OF_VECTOR, nullptr, nullptr, nullptr ));
    if( poDS == nullptr )
       {
           qDebug()<<"fail to open shp"<<endl;
           exit( 1 );
       }

    //读取各层各要素数据
    int layerNumber = poDS->GetLayerCount();            //获取图层数量

    for (int i = 0; i<layerNumber ; i++)
    {
        //遍历所有图层
        geoLayer *layer=new geoLayer();
        map->geoLayers.append(layer);

        OGRLayer  *poLayer = poDS->GetLayer( i );
        OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();

        poLayer->ResetReading();        //reset了以后，从第一个要素开始
        OGRFeature *poFeature=nullptr;
        while( (poFeature = poLayer->GetNextFeature()) != nullptr )       //遍历所有要素
        {
            //读取几何信息
            OGRGeometry *poGeometry = poFeature->GetGeometryRef();
            GetGeometry geo;
            geo.poGeometry = poGeometry;
            geoObject *newObject;

            if( poGeometry != nullptr)
            {
                auto GeometryType = wkbFlatten(poGeometry->getGeometryType());
                if (GeometryType == wkbPoint)		// 1.点
                {
                    newObject=new geoPoint();
                    newObject->type="Point";
                    double x, y, z;
                    geo.Get_Point(x,y,z);
                    newObject->coordinates.append(QPointF(x,y));
                    newObject->projectedCoordinates.append(QPointF(x,y));
                }
                else if (GeometryType == wkbLineString)		// 2.线
                {
                    newObject = new geoLineString;
                    newObject->type="LineString";
                    qDebug()<<"linestring"<<endl;
                    QVector<double> coordinatesX;
                    QVector<double> coordinatesY;
                    QVector<double> coordinatesZ;
                    geo.Get_LineString(coordinatesX, coordinatesY, coordinatesZ);
                    for(int i=0;i<coordinatesX.size();i++)
                    {
                        newObject->coordinates.append(QPointF(coordinatesX[i],coordinatesY[i]));
                        newObject->projectedCoordinates.append(QPointF(coordinatesX[i],coordinatesY[i]));
                    }
                }
                else if (GeometryType == wkbPolygon)		// 3.面
                {
                    newObject = new geoPolygon;
                    newObject->type="Polygon";
                    QMap<QString, QVector<double>> coordinates;		// 外环
                    QMap<int, QMap<QString, QVector<double>>> innerring;	//内环
                    geo.Get_Polygon(coordinates, innerring);
                    for(int i=0;i<coordinates["X"].size();i++)
                    {
                        newObject->coordinates.append(QPointF(coordinates["X"][i],coordinates["Y"][i]));
                        newObject->projectedCoordinates.append(QPointF(coordinates["X"][i],coordinates["Y"][i]));
                    }
                 }
                else if (GeometryType == wkbMultiPoint)		// 4
                {
//                    qDebug()<< "multiPoint" << endl;
                }
                else if (GeometryType == wkbMultiLineString)	// 5
                {
//                    qDebug()<<"multiLineString" << endl;
                }
                else if (GeometryType == wkbMultiPolygon)		// 6
                {
                    newObject=new geoMultiPolygon();
                    newObject->type="MultiPolygon";
                    double x,y,z;
//                    qDebug()<< "multiPolygon" << endl;
                }
                else if (GeometryType == wkbGeometryCollection)		// 7
                {
//                    qDebug()<< "geometryCollection" << endl;
                }
                else if (GeometryType == wkbNone)
                {
//                    qDebug()<<"table only" << endl;
                }
            }
            else
            {
//                qDebug()<<"no geometry"<<endl;
            }

            //读取属性信息
            for( int iField = 0; iField < poFDefn->GetFieldCount(); iField++ )  //遍历所有属性
            {
                OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn( iField );
//                qDebug()<<poFieldDefn->GetNameRef();
                switch( poFieldDefn->GetType() )
                {
                case OFTInteger:
//                    qDebug()<<poFeature->GetFieldAsInteger( iField );
                    break;
                case OFTInteger64:
//                    qDebug()<<poFeature->GetFieldAsInteger64( iField );
                    break;
                case OFTReal:
//                    qDebug()<<poFeature->GetFieldAsDouble( iField );
                    break;
                case OFTString:
//                    qDebug()<<poFeature->GetFieldAsString( iField );
                    break;
                default:
//                    qDebug()<<poFeature->GetFieldAsString( iField );
                    break;
                }
            }
            //newLayer->addObject(newObject);
            layer->geoObjects.append(newObject);

            OGRFeature::DestroyFeature( poFeature );
        }
    }

    //关闭shp文件
    GDALClose( poDS );
}

//打开核密度分析参数选择窗口
void MainWindow::onKernelAnalysis()
{
    form=new kernelAnalysisForm();
    form->show();
}

//选择要绘制的索引
void MainWindow::onActionGridIndexPressed()
{
    //同一时间只能显示一种索引
    QAction *actionGridIndex=ui->menu_4->actions()[0];
    QAction *actionQuadTreeIndex=ui->menu_4->actions()[1];
    if(actionGridIndex->isChecked()==true&&actionQuadTreeIndex->isChecked()==true)  actionQuadTreeIndex->setChecked(false);

    foreach(FileDrawWindow *window,fileDrawWindows)
    {
        gridIndex* index=window->openglWidget->getGridIndex();
        geoMap*map=&window->openglWidget->map;
        fileDrawWidget* openglWidget=window->openglWidget;
        if(index->isInitialized==false)
        {
            if(map->isProjected==false)
                index->initialize(openglWidget->projMinX,openglWidget->projMaxX,openglWidget->projMinY,openglWidget->projMaxY,map);
            else
                index->initialize(openglWidget->minX,openglWidget->maxX,openglWidget->minY,openglWidget->maxY,map);
        }
        window->openglWidget->setCurrentIndex(index);
    }
}

void MainWindow::onActionQuadTreeIndexPressed()
{
    //与网格索引的槽函数相似
    QAction *actionGridIndex=ui->menu_4->actions()[0];
    QAction *actionQuadTreeIndex=ui->menu_4->actions()[1];
    if(actionGridIndex->isChecked()==true&&actionQuadTreeIndex->isChecked()==true)  actionGridIndex->setChecked(false);

    foreach(FileDrawWindow *window,fileDrawWindows)
    {
        quadTreeIndex* index=window->openglWidget->getQuadTreeIndex();
        geoMap*map=&window->openglWidget->map;
        fileDrawWidget* openglWidget=window->openglWidget;
        if(index->isInitialized==false)
        {
            if(map->isProjected==false)
                index->initialize(openglWidget->projMinX,openglWidget->projMaxX,openglWidget->projMinY,openglWidget->projMaxY,map);
            else
                index->initialize(openglWidget->minX,openglWidget->maxX,openglWidget->minY,openglWidget->maxY,map);
        }
        window->openglWidget->setCurrentIndex(index);
    }
}
